#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "sqlite3.h"
#include "database.h"

#define CHECK(db, expr, ret)                                            \
    if ((expr) != SQLITE_OK) {                                          \
        fprintf(stderr, "sqlite3: %s\n", sqlite3_errmsg((db)->db));     \
        return ret;                                                     \
    }

static const char *SQL_TABLE_EMAIL =
    "CREATE TABLE IF NOT EXISTS email"
    "(id INTEGER PRIMARY KEY, user, message)";

static const char *SQL_SEND_EMAIL =
    "INSERT INTO email (user, message) VALUES (?, ?)";

static const char *SQL_LIST_EMAIL =
    "SELECT id, message FROM email WHERE user = ?";

static const char *SQL_DELETE_EMAIL =
    "DELETE FROM email WHERE id = ?";

//******************

static const char *SQL_TABLE_USER_INFO =
    "CREATE TABLE IF NOT EXISTS user_info"
    "(id INTEGER PRIMARY KEY, user VARCHAR UNIQUE, password)";
    
static const char *SQL_SEND_USER_INFO =
    "INSERT INTO user_info (user, password) VALUES (?, ?)";

static const char *SQL_LIST_USER_INFO =
    "SELECT id, user FROM user_info WHERE user = ? AND password = ?";

static const char *SQL_DELETE_USER_INFO =
    "DELETE FROM user_info WHERE id = ?";




int database_open(struct database *db, const char *file)
{
    if (sqlite3_open(file, &db->db) != 0)
        return -1;
    CHECK(db, sqlite3_exec(db->db, SQL_TABLE_EMAIL, NULL, NULL, NULL), -1);
    CHECK(db, sqlite3_prepare_v2(db->db, SQL_SEND_EMAIL, -1, &db->send_email, NULL), -1);
    CHECK(db, sqlite3_prepare_v2(db->db, SQL_LIST_EMAIL, -1, &db->list_email, NULL), -1);
    CHECK(db, sqlite3_prepare_v2(db->db, SQL_DELETE_EMAIL, -1, &db->del_email, NULL), -1);

    CHECK(db, sqlite3_exec(db->db, SQL_TABLE_USER_INFO, NULL, NULL, NULL), -1);
    CHECK(db, sqlite3_prepare_v2(db->db, SQL_SEND_USER_INFO, -1, &db->send_user_info, NULL), -1);
    CHECK(db, sqlite3_prepare_v2(db->db, SQL_LIST_USER_INFO, -1, &db->list_user_info, NULL), -1);
    CHECK(db, sqlite3_prepare_v2(db->db, SQL_DELETE_USER_INFO, -1, &db->del_user_info, NULL), -1);
    return 0;
}

int database_close(struct database *db)
{
    return sqlite3_close(db->db);
}
/****************** email ****************/
int database_send_email(struct database *db, const char *user, const char *message)
{
    CHECK(db, sqlite3_reset(db->send_email), -1);
    CHECK(db, sqlite3_bind_text(db->send_email, 1, user, -1, SQLITE_TRANSIENT), -1);
    CHECK(db, sqlite3_bind_blob(db->send_email, 2, message,
                                strlen(message), SQLITE_TRANSIENT), -1);
    return sqlite3_step(db->send_email) == SQLITE_ROW ? 0 : -1;
}

struct message_email *
database_list_email(struct database *db, const char *user)
{
    CHECK(db, sqlite3_reset(db->list_email), NULL);
    CHECK(db, sqlite3_bind_text(db->list_email, 1, user, -1, SQLITE_TRANSIENT),
          NULL);
    struct message_email *messages = NULL;
    while (sqlite3_step(db->list_email) == SQLITE_ROW) 
    {
        int id = sqlite3_column_int(db->list_email, 0);
        const void *blob = sqlite3_column_blob(db->list_email, 1);
        int length = sqlite3_column_bytes(db->list_email, 1);
        struct message_email *message = malloc(sizeof(*message) + length);
        memcpy(message->content, blob, length);
        message->id = id;
        message->length = length;
        message->next = messages;
        messages = message;
    }
    return messages;
}

int database_delete_email(struct database *db, int id)
{
    CHECK(db, sqlite3_reset(db->del_email), -1);
    CHECK(db, sqlite3_bind_int(db->del_email, 1, id), -1);
    while (sqlite3_step(db->del_email) == SQLITE_ROW);
    return 0;
}

/******************user info****************/
int database_send_user_info(struct database *db, const char *user, const char *password)
{
    CHECK(db, sqlite3_reset(db->send_user_info), -1);
    CHECK(db, sqlite3_bind_text(db->send_user_info, 1, user, -1, SQLITE_TRANSIENT), -1);
    CHECK(db, sqlite3_bind_blob(db->send_user_info, 2, password,
                                strlen(password), SQLITE_TRANSIENT), -1);
    int ret = sqlite3_step(db->send_user_info);
    DEBUG_PRINT("%d\r\n",ret);
    if(ret == SQLITE_DONE ||ret ==  SQLITE_ROW)
    {
        return 0;
    }
    return -1;
}

struct message_email *
database_list_user_info(struct database *db, const char *user,const char *password)
{
    CHECK(db, sqlite3_reset(db->list_user_info), NULL);
    CHECK(db, sqlite3_bind_text(db->list_user_info, 1, user, -1, SQLITE_TRANSIENT),NULL);
    CHECK(db, sqlite3_bind_blob(db->list_user_info, 2, password,
                                strlen(password), SQLITE_TRANSIENT), NULL);
    struct message_email *messages = NULL;
    while (sqlite3_step(db->list_user_info) == SQLITE_ROW) 
    {
        int id = sqlite3_column_int(db->list_user_info, 0);
        const void *blob = sqlite3_column_blob(db->list_user_info, 1);
        int length = sqlite3_column_bytes(db->list_user_info, 1);
        struct message_email *message = malloc(sizeof(*message) + length);
        memcpy(message->content, blob, length);
        message->id = id;
        message->length = length;
        message->next = messages;
        messages = message;
    }
    return messages;
}

int database_delete_user_info(struct database *db, int id)
{
    // CHECK(db, sqlite3_reset(db->del_email), -1);
    // CHECK(db, sqlite3_bind_int(db->del_email, 1, id), -1);
    // while (sqlite3_step(db->del_email) == SQLITE_ROW);
    return 0;
}